//
//  KVMutableSet.m
//  SolarSeek
//
//  Created by Erick Fejta on 05/05/21.
//  Copyright 2005 __MyCompanyName__. All rights reserved.
//

#import "KVMutableSet.h"

@interface KVMutableSet (Private)
- (void)addObject:(id)o delay:(NSTimeInterval)delay;
- (void)removeObject:(id)o delay:(NSTimeInterval)delay;
- (void)removeAllObjects;
@end

@interface KVMutableSetContainer : NSMutableSet {
	NSMutableSet *_set;
	KVMutableSet *_kvm;
}

- (id)initWith:(KVMutableSet *)parent;

- (void)addObject:(id)object;
- (void)addObject:(id)object allowDelay:(NSTimeInterval)delay;

- (void)removeObject:(id)object;
- (void)addObject:(id)object allowDelay:(NSTimeInterval)delay;
- (void)removeObject:(id)object allowDelay:(NSTimeInterval)delay;

- (unsigned)count;
- (id)member:(id)o;
- (NSEnumerator *)objectEnumerator;

@end

@implementation KVMutableSetContainer

- (id)initWith:(KVMutableSet *)parent {
	self = [super init];
	if(self) {
		_set = [[NSMutableSet alloc] init];
		_kvm = parent;
	}
	return self;
}
- (void)dealloc { 
	[_set release];
	[super dealloc];
}

- (unsigned)count { return [_set count]; }
- (id)member:(id)o { 
	id o2 = [_set member:o]; 
	return o2;
}
- (NSEnumerator *)objectEnumerator { return [_set objectEnumerator]; }


- (void)addObject:(id)o { [self addObject:o allowDelay:[_kvm defaultDelay]]; }
- (void)addObject:(id)o allowDelay:(NSTimeInterval)delay{
	unsigned old = [self count];
	[_set addObject:o];
	if(old != [self count]) {
		[_kvm addObject:o delay:delay];
	}
}

- (void)removeObject:(id)o { [self removeObject:o allowDelay:[_kvm defaultDelay]]; }
- (void)removeObject:(id)o allowDelay:(NSTimeInterval)delay { 
	unsigned old = [self count];
	[_set removeObject:o];
	if([self count] != old) {
		[_kvm removeObject:o delay:delay];
	}
}

- (void)removeAllObjects; { 
	[_set removeAllObjects];
	[_kvm removeAllObjects];
}
@end

@implementation KVMutableSet
- (id)init {
	return [self initWithDefaultDelay:0.01];
}


- (id)initWithDefaultDelay:(NSTimeInterval)delay {
	if(self = [super init]) {
		_defaultDelay = delay;
		_array = [[NSMutableArray alloc] init];
		_pendingIn = [[NSMutableArray alloc] init];
		_pendingOut = [[NSMutableArray alloc] init];
		_set = [[KVMutableSetContainer alloc] initWith:self];
	}
	
	return self;
}

- (void)dealloc {
	[_array release];
	_array = nil;
	[_set release];
	_set = nil;
	[_pendingIn release];
	[_pendingOut release];
	_pendingIn = _pendingOut = nil;
	[super dealloc];
}


- (void)setDefaultDelay:(NSTimeInterval)delay { _defaultDelay = delay; }
- (NSTimeInterval)defaultDelay { return _defaultDelay; }

- (unsigned)count { return [_set count]; }

- (NSArray *)values { return _array; }
- (unsigned)countOfValues { 
	unsigned c = [_array count]; 
	return c;
}
- (id)objectInValuesAtIndex:(unsigned)idx { return [_array objectAtIndex:idx]; }
- (void)getValues:(id *)objs range:(NSRange)range { return [_array getObjects:objs range:range]; }
- (void)insertObject:(id)obj inValuesAtIndex:(unsigned)idx { [_array insertObject:obj atIndex:idx]; }
- (void)removeObjectFromValuesAtIndex:(unsigned)idx { [_array removeObjectAtIndex:idx]; }

- (void)add {
	[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(add) object:nil];
	[self willChangeValueForKey:@"countOfValues"];
	NSArray *a = [NSArray arrayWithArray:_pendingIn];
	[_pendingIn removeAllObjects];
	NSMutableArray *add = [self mutableArrayValueForKey:@"values"];
	[add addObjectsFromArray:a];
	[self didChangeValueForKey:@"countOfValues"];
}
- (void)addObject:(id)o delay:(NSTimeInterval)delay {
	if(delay > 0.0) {
		[_pendingIn addObject:o];
		[self performSelector:@selector(add) withObject:nil afterDelay:delay];
	}
	else {
		[self willChangeValueForKey:@"countOfValues"];
		[[self mutableArrayValueForKey:@"values"] addObject:o];
		[self didChangeValueForKey:@"countOfValues"];
	}
}

- (void)remove {
	[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(remove) object:nil];
	[self willChangeValueForKey:@"countOfValues"];
	NSArray *a = [NSArray arrayWithArray:_pendingOut];
	[_pendingOut removeAllObjects];
	NSMutableArray *rem = [self mutableArrayValueForKey:@"values"];
	[rem removeObjectsInArray:a];
	[self didChangeValueForKey:@"countOfValues"];
}

- (void)removeObject:(id)o delay:(NSTimeInterval)delay {
	if(delay > 0.0) {
		[_pendingOut addObject:o];
		[self performSelector:@selector(remove) withObject:nil afterDelay:delay];
	}
	else {
		[self willChangeValueForKey:@"countOfValues"];
		[[self mutableArrayValueForKey:@"values"] removeObject:o];
		[self didChangeValueForKey:@"countOfValues"];
	}
}

- (void)removeAllObjects {
	if([_pendingOut count])
		[self remove];
	else if([_pendingIn count])
		[self add];
	[self willChangeValueForKey:@"countOfValues"];
	[[self mutableArrayValueForKey:@"values"] removeAllObjects];
	[self didChangeValueForKey:@"countOfValues"];
}

- (NSString *)description { return @"SET"; }

- (NSMutableSet *)mutableSet { return _set; }

@end